#pragma once

#include<iostream>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

namespace tcpserver
{
	typedef void(*handler_t)(int);
	const int backlog = 5;

	class TcpServer
	{
		private:
			uint16_t port;
			int listen_sock;
		public:
			TcpServer(int _port):port(_port),listen_sock(-1){}
			void InitTcpServer()
			{
				listen_sock = socket(AF_INET,SOCK_STREAM,0);
				
				struct sockaddr_in local;

				local.sin_family = AF_INET;
				local.sin_port = htons(port);
				local.sin_addr.s_addr = INADDR_ANY;

				if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local)) < 0)
				{
					std::cerr << "bind error" << std::endl;
					exit(2);
				}
				if(listen(listen_sock,backlog) < 0)
				{
					std::cerr<< "listen error" << std::endl;
					exit(3);
				}
			}
			void Loop(handler_t handler)
			{
				while(1)
				{
					struct sockaddr_in dest;
					socklen_t len = sizeof(dest);
					int sock = accept(listen_sock,(struct sockaddr*)&dest,&len);
					if(sock < 0)
					{
						std::cout << "warning: accept error"<<std::endl;
						continue;
					}
					std::cout<< "debug sock->"<<sock<<std::endl;
					uint16_t dest_port = ntohs(dest.sin_port);
					std::string dest_ip = inet_ntoa(dest.sin_addr);

					std::cout<<"debug:"<<dest_ip<<":"<<dest_port<<std::endl;

					handler(sock);
				}
			}
			~TcpServer()
			{
				if(listen_sock >= 0)close(listen_sock);
			}
	};
}

